home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Snippets / QuickDraw / IconDimming / IconDimming.c next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  11.5 KB  |  392 lines  |  [TEXT/KAHL]

  1. /****************************************************************************/
  2. /*                                                                            */
  3. /*    Application:    IconDimming                                                */
  4. /*                                                                            */
  5. /*    Description:    In System 7, selected non-open files are shown as        */
  6. /*                    dimmed icons on the desktop.  This snippet shows        */
  7. /*                    two different ways to achieve the same results in        */
  8. /*                    an application.                                            */
  9. /*                                                                            */
  10. /*                    The first method uses a custom color search                */
  11. /*                    procedure in place of the current device's to            */
  12. /*                    create the dimming effect.  Once the image has            */
  13. /*                    been copied to the destination, the custom                */
  14. /*                    search proc is then removed.                            */
  15. /*                                                                            */
  16. /*                    In the second method the RGB components of the            */
  17. /*                    icon's colortable entries are all dimmed before            */
  18. /*                    the image is copied into the destination.  The            */
  19. /*                    dimming algorithm used in this method simply            */
  20. /*                    darkens each RGB component in half then takes            */
  21. /*                    the two smaller components and darkens them                */
  22. /*                    in half again.  In System 7, this is similar            */
  23. /*                    to what the Finder does.                                */
  24. /*                                                                            */
  25. /*    Files:            IconDimming.π                                            */
  26. /*                    IconDimming.c                                            */
  27. /*                    IconDimming.π.rsrc                                        */
  28. /*                                                                            */
  29. /*    Programmer:        Edgar Lee                                                */
  30. /*    Organization:    Apple Computer, Inc.                                    */
  31. /*    Department:        Developer Technical Support, DTS                        */
  32. /*    Language:        C (Think C version 5.0.1)                                */
  33. /*    Date Created:    2-27-92                                                    */
  34. /*                                                                            */
  35. /****************************************************************************/
  36.  
  37. /* Constant Declarations */
  38.  
  39. #define    WWIDTH        480
  40. #define    WHEIGHT        180
  41.  
  42. #define WLEFT        (((screenBits.bounds.right - screenBits.bounds.left) - WWIDTH) / 2)
  43. #define WTOP        (((screenBits.bounds.bottom - screenBits.bounds.top) - WHEIGHT) / 2)
  44.  
  45. typedef    struct
  46. {
  47.     PixMap    pixmap;        /* Pixmap used to store the icl8 pixel image. */
  48.     BitMap    mask;        /* Bitmap used to store the 1 bit mask image of the icl8. */
  49. }
  50. MyIconType;
  51.  
  52. /* Global Variable Definitions */
  53.  
  54. WindowPtr    gWindow;
  55.  
  56. void initMac();
  57. void createWindow();
  58. void loadIconResource();
  59. void doEventLoop();
  60.  
  61. void drawIconUnchanged();
  62. void drawIconUsingSearchProc();
  63. void drawIconUsingCTable();
  64.  
  65. void DimColor( RGBColor *aColor );
  66. long CompareComponents( unsigned short component0, unsigned short component1 );
  67.  
  68. static pascal Boolean SearchProc();
  69.  
  70. main()
  71. {
  72.     MyIconType    icon;
  73.     
  74.     initMac();
  75.     
  76.     createWindow();
  77.     loadIconResource( &icon );
  78.  
  79.     doEventLoop( &icon );
  80. }
  81.  
  82. void initMac()
  83. {
  84.     MaxApplZone();
  85.     
  86.     InitGraf( &thePort );
  87.     InitFonts();
  88.     InitWindows();
  89.     InitMenus();
  90.     TEInit();
  91.     InitDialogs( nil );
  92.     InitCursor();
  93.     FlushEvents( 0, everyEvent );
  94. }
  95.  
  96. void createWindow()
  97. {
  98.     Rect rect;
  99.     
  100.     SetRect( &rect, WLEFT, WTOP, WLEFT + WWIDTH, WTOP + WHEIGHT );
  101.     
  102.     gWindow = NewCWindow( 0L, &rect, "\pIconDimming", true, noGrowDocProc,
  103.                             (WindowPtr)-1L, true, 0L );
  104.     SetPort( gWindow );
  105.     
  106.     TextFont( geneva );
  107.     TextSize( 9 );
  108. }
  109.  
  110. void loadIconResource( icon )
  111. MyIconType    *icon;
  112. {
  113.     Handle        icnHandle;        /* Handle to the icon bitmap used for the mask. */
  114.     Handle        iclHandle;        /* Handle to the icl8 resource. */
  115.     char        depth;            /* Depth of the icl8 image. */
  116.     Rect        rect;            /* Bounding rect for the image. */
  117.     
  118.     SetRect( &rect, 0, 0, 32, 32 );
  119.     depth = 8;
  120.     
  121.     /* Create the mask. */
  122.     
  123.     icnHandle = GetResource( 'ICN#', 129 );
  124.     
  125.     HLock( icnHandle );
  126.     HNoPurge( icnHandle );
  127.     
  128.     (*icon).mask.baseAddr = *icnHandle + (4 * 32);
  129.     (*icon).mask.rowBytes = 4;
  130.     (*icon).mask.bounds = rect;
  131.     
  132.     /* Create a pixmap for the icl8 pixel image. */
  133.     
  134.     iclHandle = GetResource( 'icl8', 129 );
  135.     
  136.     HLock( iclHandle );
  137.     HNoPurge( iclHandle );
  138.     
  139.     (*icon).pixmap.baseAddr = *iclHandle;
  140.     (*icon).pixmap.rowBytes = ((32 * depth) / 8) | 0x8000;
  141.     (*icon).pixmap.bounds = rect;
  142.     (*icon).pixmap.pmVersion = 0;
  143.     (*icon).pixmap.packType = 0;
  144.     (*icon).pixmap.packSize = 0;
  145.     (*icon).pixmap.hRes = 72;
  146.     (*icon).pixmap.vRes = 72;
  147.     (*icon).pixmap.pixelSize = depth;
  148.     (*icon).pixmap.planeBytes = 0;
  149.     (*icon).pixmap.pmReserved = 0;
  150.     (*icon).pixmap.pixelType = 0;
  151.     (*icon).pixmap.cmpCount = 1;
  152.     (*icon).pixmap.cmpSize = depth;
  153.     (*icon).pixmap.pmTable = GetCTable( depth );
  154.     
  155.     /* Give a unique seed for the pixmap's colortable.  Note that this is        */
  156.     /*    necessary for two reasons.  (1) The pixmap's colortable is ignored by    */
  157.     /*    copybits or copymask if the source ctable's ctseed value matches that    */
  158.     /*    of the    destination's.  (2) Matching ctseed values prevent any custom    */
  159.     /*    searchProcs from being called.                                            */
  160.     
  161.     (**(*icon).pixmap.pmTable).ctSeed = GetCTSeed();
  162. }
  163.  
  164. void drawIconUnchanged( icon )
  165. MyIconType    *icon;
  166. {
  167.     Str255        title = "\pOriginal 'icl8'";
  168.     Rect        rect;
  169.  
  170.     /* Draw the original icl8 image unchanged. */
  171.     
  172.     SetRect( &rect, 0, 0, 160, 160 );
  173.     CopyMask( (BitMap *)&(*icon).pixmap, &(*icon).mask, &gWindow->portBits,
  174.                 &(*icon).pixmap.bounds, &(*icon).mask.bounds, &rect );
  175.                 
  176.     MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left,
  177.             rect.bottom + 15 );
  178.     DrawString( title );
  179. }
  180.  
  181. void drawIconUsingSearchProc( icon )
  182. MyIconType    *icon;
  183. {
  184.     Str255        title = "\p'icl8' using SearchProc Dimming";
  185.     Rect        rect;
  186.     GWorldPtr    gworld;            /* Offscreen used for the custom search procedure. */
  187.     CGrafPtr    currentPort;    /* Saved CGrafPort for later restore. */
  188.     GDHandle    currentDevice;    /* Saved gdDevice for later restore. */
  189.     
  190.     GetGWorld( ¤tPort, ¤tDevice );
  191.     
  192.     /* Install the custom search proc to an offscreen pixmap instead of the    */
  193.     /*    screen's in order to be courteous to other apps.                    */
  194.         
  195.     NewGWorld( &gworld, 8, &(*icon).pixmap.bounds, GetCTable( 8 ), nil, 0 );
  196.     HLock( (*gworld).portPixMap );
  197.         
  198.     SetGWorld( gworld, nil );
  199.     AddSearch( SearchProc );
  200.  
  201.     CopyBits( &(*icon).pixmap, &(*gworld).portPixMap, &(*icon).pixmap.bounds,
  202.                 &(**(*gworld).portPixMap).bounds, srcCopy, nil );
  203.     
  204.     DelSearch( SearchProc );
  205.     SetGWorld( currentPort, currentDevice );
  206.     
  207.     /* Now copy the dimmed pixmap image to the window. */
  208.     
  209.     rect.left = (*icon).pixmap.bounds.right * 5;
  210.     rect.top = (*icon).pixmap.bounds.top;
  211.     rect.right = (*icon).pixmap.bounds.right * 5 + rect.left;
  212.     rect.bottom = (*icon).pixmap.bounds.bottom * 5;
  213.  
  214.     CopyMask( &(*gworld).portPixMap, &(*icon).mask, &gWindow->portBits,
  215.                 &(**(*gworld).portPixMap).bounds, &(*icon).mask.bounds, &rect );
  216.     
  217.     DisposeGWorld( gworld );
  218.     
  219.     MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left,
  220.             rect.bottom + 15 );
  221.     DrawString( title );
  222. }
  223.  
  224. static pascal Boolean SearchProc( color, position )
  225. RGBColor    *color;
  226. long        *position;
  227. {
  228.     /* Darken the RGB components in half.  Note that this routine could just    */
  229.     /*    have easily called DimColor; however, I wanted to show the difference    */
  230.     /*    between just dimming the components in half to what System 7 does.         */
  231.         
  232.     color->red >>= 1;
  233.     color->green >>= 1;
  234.     color->blue >>= 1;
  235.     
  236.     return false;
  237. }
  238.  
  239. void drawIconUsingCTable( icon )
  240. MyIconType    *icon;
  241. {
  242.     Str255        title = "\p'icl8' using Colortable Dimming";
  243.     Rect        rect;
  244.     short        index;            /* Index into the dimmed colortable */
  245.     CTabHandle    dimmedClut;     /* Holds dimmed version of icon’s colortable */
  246.     CTabHandle    savedClut;        /* Saves the icon’s original colortable */
  247.     
  248.     /* Save the icon’s color table and make a copy of it */
  249.     dimmedClut = savedClut = (*icon).pixmap.pmTable;
  250.     HandToHand( (CTabHandle *)&dimmedClut );
  251.  
  252.     /* Dim each of the colors in the copy of the color table */
  253.     for (index = 0; index <= (**dimmedClut).ctSize; ++index)
  254.         DimColor( &(**dimmedClut).ctTable[index].rgb );
  255.  
  256.     /* Install the dimmed copy of the color table */
  257.     (*icon).pixmap.pmTable = dimmedClut;
  258.     
  259.     rect.left = (*icon).pixmap.bounds.right * 10;
  260.     rect.top = (*icon).pixmap.bounds.top;
  261.     rect.right = (*icon).pixmap.bounds.right * 5 + rect.left;
  262.     rect.bottom = (*icon).pixmap.bounds.bottom * 5;
  263.     
  264.     /* Now copy the dimmed pixmap image to the window. */
  265.     
  266.     CopyMask( (BitMap *)&(*icon).pixmap, &(*icon).mask, &gWindow->portBits,
  267.                 &(*icon).pixmap.bounds, &(*icon).mask.bounds, &rect );
  268.     
  269.     (*icon).pixmap.pmTable = savedClut;
  270.     DisposCTable( dimmedClut );
  271.  
  272.     MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left,
  273.             rect.bottom + 15 );
  274.     DrawString( title );
  275. }
  276.  
  277. /******************************************************************************\
  278. * DimColor - Dim one color for selection
  279. *        written by Forrest Tanaka
  280. * This routine dims the color that’s passed in the aColor parameter so that
  281. * it’s suitable to use for making an icon look selected.  It works by dimming
  282. * all components by half, and then dimming the smaller two components by half
  283. * again.  By keeping the largest component dimmed by only half, we keep the
  284. * saturation of the color approximately what it was before it was dimmed.
  285. \******************************************************************************/
  286.  
  287. void DimColor( 
  288.     RGBColor *aColor)
  289. {
  290.     unsigned short *biggest; /* Pointer to the biggest component */
  291.  
  292.     /* Dim all components by half */
  293.     aColor->red >>= 1;
  294.     aColor->green >>= 1;
  295.     aColor->blue >>= 1;
  296.  
  297.     /* If aColor isn’t nearly gray, dim smallest 2 components again by half */
  298.     if (CompareComponents( aColor->red, aColor->green ) != 0 ||
  299.             CompareComponents( aColor->red, aColor->blue ) != 0)
  300.     {
  301.         /* Point to the larger of red and green */
  302.         if (CompareComponents( aColor->red, aColor->green ) > 0)
  303.             biggest = &aColor->red;
  304.         else
  305.             biggest = &aColor->green;
  306.  
  307.         /* Point to the larger of previous test and blue */
  308.         if (CompareComponents( aColor->blue, *biggest ) > 0)
  309.             biggest = &aColor->blue;
  310.  
  311.         /* Dim smaller two components by half */
  312.         if (&aColor->red != biggest)
  313.             aColor->red >>= 1;
  314.         if (&aColor->green != biggest)
  315.             aColor->green >>= 1;
  316.         if (&aColor->blue != biggest)
  317.             aColor->blue >>= 1;
  318.     }
  319. }
  320.  
  321. /******************************************************************************\
  322. * CompareComponents - Compare two components for difference and equality
  323. *        written by Forrest Tanaka
  324. * This routine compares two components of an RGBColor that are passed in the
  325. * component0 and component1 parameters.  If they’re within 512 units of each
  326. * other, then zero is returned.  Otherwise, the positive difference is returned
  327. * if component0 is greater than component1, or the negative of the difference
  328. * is returned if component1 is greater than component0.
  329. \******************************************************************************/
  330.  
  331. long CompareComponents(
  332.     unsigned short component0, /* First component to check */
  333.     unsigned short component1) /* Second component to check */
  334. {
  335.     long difference; /* Difference between components */
  336.  
  337.     /* Calculate the difference between the components */
  338.     difference = (unsigned long)component0 - (unsigned long)component1;
  339.  
  340.     /* If the difference is within 512 units, then consider the components the same */
  341.     if ((difference < 512) && (difference > -512))
  342.         return 0;
  343.     else
  344.         return difference;
  345. }
  346.  
  347. void doEventLoop( icon )
  348. MyIconType    *icon;
  349. {
  350.     EventRecord event;
  351.     WindowPtr   window;
  352.     short       clickArea;
  353.     Rect        screenRect;
  354.  
  355.     for (;;)
  356.     {
  357.         if (WaitNextEvent( everyEvent, &event, 0, nil ))
  358.         {
  359.             if (event.what == mouseDown)
  360.             {
  361.                 clickArea = FindWindow( event.where, &window );
  362.                 
  363.                 if (clickArea == inDrag)
  364.                 {
  365.                     screenRect = (**GetGrayRgn()).rgnBBox;
  366.                     DragWindow( window, event.where, &screenRect );
  367.                 }
  368.                 else if (clickArea == inContent)
  369.                 {
  370.                     if (window != FrontWindow())
  371.                         SelectWindow( window );
  372.                 }
  373.                 else if (clickArea == inGoAway)
  374.                     if (TrackGoAway( window, event.where ))
  375.                         return;
  376.             }
  377.             else if (event.what == updateEvt)
  378.             {
  379.                 window = (WindowPtr)event.message;    
  380.                 SetPort( window );
  381.                 
  382.                 BeginUpdate( window );
  383.                 
  384.                 drawIconUnchanged( icon );
  385.                 drawIconUsingSearchProc( icon );
  386.                 drawIconUsingCTable( icon );
  387.                 
  388.                 EndUpdate( window );
  389.             }
  390.         }
  391.     }
  392. }